﻿using System;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
using System.Xml;
using XiaoSe.XML.Sgml;
using System.Xml.XPath;

namespace XiaoSe.Web
{
    public class HtmlHelper
    {
        public string[] TagBlackList;
        public bool IsOpenTagsBlackList;
        public string[] AttrWhiteList;
        public bool IsOpenAttrWhileList;
        public string GetSafeHtml(string strHtml, bool isOpenTagsBlackList, bool isOpenAttrWhileList, string[] tagBlackList, string[] attrWhiteList)
        {
            if (string.IsNullOrEmpty(strHtml))
                return "";
            IsOpenTagsBlackList = isOpenTagsBlackList;
            TagBlackList = tagBlackList;
            AttrWhiteList = attrWhiteList;
            IsOpenAttrWhileList = isOpenAttrWhileList;
            strHtml = ResolveHtml(strHtml,null);
            strHtml = Regex.Replace(strHtml, "<script.{0,}?>", "&lt;script&gt;", RegexOptions.IgnoreCase);
            strHtml = Regex.Replace(strHtml, "</script>", "&lt;/script&gt;", RegexOptions.IgnoreCase);
            const string strRegex = "<([a-z]{1,10})(( \\w{1,}=\".{0,}\"){0,})([(>)|(/>)])";
            var r = new Regex(strRegex, RegexOptions.IgnoreCase);
            strHtml = r.Replace(strHtml, SafeHtmlTags);
            return strHtml;
        }
        public string ResolveHtml(string content, string xpath)
        {
            if (string.IsNullOrEmpty(content))
            {
                return "";
            }
            StringWriter sw = null;
            SgmlReader reader = null;
            XmlTextWriter writer = null;
            try
            {
                content = "<ResolveHtml>" + content + "</ResolveHtml>";
                reader = new SgmlReader { DocType = "HTML", InputStream = new StringReader(content) };
                sw = new StringWriter();
                writer = new XmlTextWriter(sw) { Formatting = Formatting.Indented };
                while (reader.Read())
                {
                    if (reader.NodeType != XmlNodeType.Whitespace)
                    {
                        writer.WriteNode(reader, true);
                    }
                }
                if (xpath == null)
                {
                    content = sw.ToString();
                    content = content.Substring(13);
                    content = content.Substring(0, content.Length - 14);
                    return content;
                }
                var sb = new StringBuilder();
                var doc = new XPathDocument(new StringReader(sw.ToString()));
                var nav = doc.CreateNavigator();
                var nodes = nav.Select(xpath);
                while (nodes.MoveNext())
                {
                    sb.Append(nodes.Current.Value + " ");
                }
                return sb.ToString();
            }
            catch (Exception exp)
            {
                if (writer != null) writer.Close();
                if (reader != null) reader.Close();
                if (sw != null) sw.Close();
                return exp.Message;
            }
            finally
            {
                if (writer != null) writer.Close();
                if (reader != null) reader.Close();
                if (sw != null) sw.Close();
            }
        }
        private string SafeHtmlTags(Match m)
        {
            var tags = m.Value;
            if (!string.IsNullOrEmpty(tags))
            {
                if (IsOpenTagsBlackList && TagBlackList != null)
                {
                    foreach (var black in TagBlackList)
                    {
                        if (Regex.Match(tags, black).Success)
                        {
                            return "";
                        }
                    }
                }
                const string strRegex = " (\\w{1,}=\".{0,}?\")";
                var r = new Regex(strRegex, RegexOptions.IgnoreCase);
                tags = r.Replace(tags, SafeHtmlAttr);
                return tags;
            }
            return "";
        }
        private string SafeHtmlAttr(Match m)
        {
            var tags = m.Value;
            if (!string.IsNullOrEmpty(tags))
            {
                if (IsOpenAttrWhileList && AttrWhiteList != null)
                {
                    foreach (var white in AttrWhiteList)
                    {
                        if (Regex.Match(tags, white).Success)
                        {
                            return tags;
                        }
                    }
                }
            }
            return "";
        }
    }
}
